home *** CD-ROM | disk | FTP | other *** search
/ Thailand - Into the 2000's / Thailand: Into the 2000's.iso / Acrobat / Javascripts / Annots.js < prev   
Text File  |  2001-08-01  |  23KB  |  863 lines

  1. if(typeof Collab != "undefined")
  2. {
  3.     var strsToExport =[
  4.         "IDS_SUM_TITLE1",
  5.         "IDS_SUM_TITLE2",
  6.         "IDS_UNNAMED",
  7.         "IDS_SUM_DATE1",
  8.         "IDS_SUM_DATE2",
  9.         "IDS_SUM_AUTHOR1",
  10.         "IDS_SUM_AUTHOR2",
  11.         "IDS_SUM_SUBJ1",
  12.         "IDS_SUM_SUBJ2",
  13.         "IDS_SUM_LABEL1",
  14.         "IDS_SUM_LABEL2",
  15.         "IDS_SUM_PAGE1",
  16.         "IDS_SUM_PAGE2",
  17.         "IDS_SUM_TYPE1",
  18.         "IDS_SUM_TYPE2",
  19.         "IDS_SUM_SEQ1",
  20.         "IDS_SUM_SEQ2",
  21.         "IDS_SUM_NO_ANNOTS1",
  22.         "IDS_SUM_NO_ANNOTS2",
  23.         "IDS_STORE_WEB_DISCUSSIONS",
  24.         "IDS_STORE_DAVFDF",
  25.         "IDS_STORE_FSFDF",
  26.         "IDS_STORE_DATABASE",
  27.         "IDS_STORE_NONE",
  28.         "IDS_PROGRESS_SUMMARIZE",
  29.         "IDS_PROGRESS_SORTING",
  30.         "IDS_PROGRESS_FETCHING",
  31.         "IDS_PROGRESS_FETCHING_BIG",
  32.         "IDS_PROGRESS_ADDING",
  33.         "IDS_PROGRESS_DELETING",
  34.         "IDS_PROGRESS_CHANGING",
  35.         "IDS_ANNOTS_JS_BUILTIN",
  36.         "IDS_DATE_INDETERMINATE"
  37.     ];
  38.  
  39.     for(var n = 0; n < strsToExport.length; n++)
  40.     {
  41.         var strID = strsToExport[n];
  42.  
  43.         eval(strID + " = " + app.getString("Annots", strID).toSource());
  44.     }
  45.  
  46.     console.println(IDS_ANNOTS_JS_BUILTIN);
  47.  
  48.     /* for debugging */
  49.     function debugExcept(e)
  50.     {
  51.         if((typeof app._DEBUG != "undefined") && app._DEBUG)
  52.           console.println(e)
  53.     }
  54.  
  55.     /* Sort methods */
  56.     ANSB_None = 0;
  57.     ANSB_Page = 1;
  58.     ANSB_Seq = 2;
  59.     ANSB_Author = 3;
  60.     ANSB_ModDate = 4;
  61.     ANSB_Type = 5;
  62.  
  63.     ANFB_ShouldPrint = 0;
  64.     ANFB_ShouldView = 1;
  65.     ANFB_ShouldEdit = 2;
  66.     ANFB_ShouldAppearInPanel = 3;
  67.     ANFB_ShouldSummarize = 4;
  68.     ANFB_ShouldExport = 5;
  69.     ANFB_ShouldNone = 6;
  70.  
  71.     /* Field to summary functions by property name */
  72.     ANsums =
  73.     [
  74.     /* None */        function(a){return "*None*";},
  75.     /* Page */        function(a){return IDS_SUM_PAGE1+a.doc.getPageLabel(a.page)+IDS_SUM_PAGE2;},
  76.     /* Sequence */    function(a){return IDS_SUM_SEQ1+a.seqNum+IDS_SUM_SEQ2;},
  77.     /* Author */    function(a){return IDS_SUM_AUTHOR1+a.author+IDS_SUM_AUTHOR2;},
  78.     /* ModDate */    function(a){
  79.         var d = a.modDate; 
  80.         return IDS_SUM_DATE1+ (d ? util.printd(2, a.modDate) : IDS_DATE_INDETERMINATE )+IDS_SUM_DATE2;
  81.         },
  82.     /* Type */        function(a){return IDS_SUM_TYPE1+a.uiType+IDS_SUM_TYPE2;},
  83.     ];
  84.  
  85.     /* Order of summary fields */
  86.     ANsumorder = [ ANSB_Page, ANSB_Seq, ANSB_Author, ANSB_ModDate, ANSB_Type ];
  87.  
  88.     /* binary insertion into sorted list */
  89.     function binsert(a, m)
  90.     {
  91.         var nStart = 0, nEnd = a.length - 1;
  92.  
  93.         while(nStart < nEnd)
  94.         {
  95.             var nMid = Math.floor((nStart + nEnd) / 2);
  96.  
  97.             if(m.toString() < a[nMid].toString())
  98.                 nEnd = nMid - 1;
  99.             else
  100.                 nStart = nMid + 1;
  101.         }
  102.         if((nStart < a.length) && (m.toString() >= a[nStart].toString()))
  103.             a.splice(nStart + 1, 0, m);
  104.         else
  105.             a.splice(nStart, 0, m);
  106.     }
  107.  
  108.     /* perform a worst case n log ( n ) sort with status */
  109.     function isort(a, status)
  110.     {
  111.         var i;
  112.         var aNew = new Array();
  113.  
  114.         if(status)
  115.         {
  116.             app.thermometer.begin();
  117.             app.thermometer.duration = a.length;
  118.             app.thermometer.text = status;
  119.         }
  120.         for(i = 0; i < a.length; i++)
  121.         {
  122.             if(status)
  123.                 app.thermometer.value = i;
  124.             binsert(aNew, a[i]);
  125.         }
  126.         if(status)
  127.             app.thermometer.end();
  128.         return aNew;
  129.     }
  130.  
  131.     function ANsummarize(doc, title, p, r, dest, fs)
  132.     {    /* Summarize annotations sorted primarily by property p */
  133.         app.thermometer.begin();
  134.         app.thermometer.text = IDS_PROGRESS_SUMMARIZE;
  135.  
  136.         if(!ANsums[p])
  137.             p = ANSB_Page;
  138.         if(!title)
  139.             title = IDS_UNNAMED;
  140.  
  141.         /* make sure we have all annots */
  142.         this.syncAnnotScan();
  143.  
  144.         /* Get all summarizable annots on all pages sorted in the given manner */
  145.         var a = doc.getAnnots(-1, p, r, ANFB_ShouldSummarize);
  146.         var t, s;
  147.         var r = new Report();
  148.  
  149.         r.style = "NoteTitle";
  150.         r.size = 3;
  151.         t = IDS_SUM_TITLE1 + title + IDS_SUM_TITLE2;
  152.         r.writeText(t);
  153.         r.divide(3.5);
  154.  
  155.         var i, j, contents;
  156.         var oldHeading;
  157.  
  158.         if(a && a.length > 0)
  159.         {
  160.           app.thermometer.duration = a.length;
  161.           for(i = 0; i < a.length; i++)
  162.           {
  163.             app.thermometer.value = i;
  164.             // maybe do the heading
  165.               r.style = "NoteTitle";
  166.               r.size = 2;
  167.               var heading = (ANsums[p])(a[i]);
  168.               if(heading != oldHeading)
  169.               {
  170.                 if(typeof oldHeading != "undefined")
  171.                   r.writeText(" ");
  172.                 r.writeText(heading);
  173.                 oldHeading = heading;
  174.                 r.divide();
  175.               }
  176.  
  177.               for(j = 0; j < ANsumorder.length; j++)
  178.                   if(ANsumorder[j] != p)
  179.                   {
  180.                       r.size = 1;
  181.                       r.writeText((ANsums[ANsumorder[j]])(a[i]));
  182.                   }
  183.               var contents = a[i].contents;
  184.               if(contents)
  185.               {
  186.                   r.style = "DefaultNoteText";
  187.                   r.size = 1;
  188.                   r.indent();
  189.                   r.writeText(contents);
  190.                   r.writeText(" ");
  191.                   r.outdent();
  192.               }
  193.               else
  194.                   r.writeText(" ");
  195.           }
  196.         }
  197.         else
  198.           r.writeText(IDS_SUM_NO_ANNOTS1 + title + IDS_SUM_NO_ANNOTS2);
  199.         if (typeof dest != "undefined")
  200.             r.save(dest, fs);
  201.         else
  202.             r.open(t);
  203.         app.thermometer.end();
  204.  
  205.         return a ? a.length : 0;
  206.     }
  207.  
  208.     /* flags used by collaboration
  209.     */
  210.     CBFNiceTableName = 1;
  211.     CBFNiceDBName = 2;
  212.     CBFDBPerDoc = 4;
  213.  
  214.     function CBgetTableDesc(doc, author)
  215.     {
  216.       var frag = Collab.URL2PathFragment(doc.URL);
  217.       var DBName;
  218.       var tableName;
  219.  
  220.       if(doc.collabDBFlags & CBFDBPerDoc)
  221.       {
  222.         DBName = frag;
  223.         tableName = author;
  224.       }
  225.       else
  226.       {
  227.         DBName = "";
  228.         tableName = frag;
  229.       }
  230.  
  231.       if(doc.collabDBFlags & CBFNiceTableName)
  232.         tableName = Collab.hashString(tableName);
  233.       if(doc.collabDBFlags & CBFNiceDBName)
  234.         DBName = Collab.hashString(DBName);
  235.       return {DBName: doc.collabDBRoot + DBName,
  236.         tableName: tableName,
  237.         URL: doc.URL,
  238.         user: author,
  239.         flags: doc.collabDBFlags};
  240.     }
  241.  
  242.     function CBgetTableConnect(desc)
  243.     {
  244.       var e;
  245.  
  246.       try
  247.       {
  248.         var conn = ADBC.newConnection(desc.DBName);
  249.         var stmt = conn.newStatement();
  250.  
  251.         return {conn: conn,
  252.           stmt: stmt,
  253.           tableName: desc.tableName,
  254.           user: desc.user,
  255.           flags: desc.flags};
  256.       }
  257.       catch(e) { debugExcept(e); return false; }
  258.     }
  259.  
  260.     function CBgetInfo(conn, name)
  261.     {
  262.       var e;
  263.  
  264.       try
  265.       {
  266.         conn.stmt.execute("select CONTENTS from \"" + conn.tableName + "\" where AUTHOR like ?;",
  267.           "~" + name + "~");
  268.         conn.stmt.nextRow();
  269.         return conn.stmt.getColumn("CONTENTS").value;
  270.       }
  271.       catch(e) { debugExcept(e); return false; }
  272.     }
  273.  
  274.     function CBsetInfo(conn, name, value)
  275.     {
  276.       var e;
  277.  
  278.       /* add the field */
  279.       try { return conn.stmt.execute("insert into \"" + conn.tableName + "\" (AUTHOR, CONTENTS) values (?, ?);",
  280.           "~" + name + "~",
  281.           value); }
  282.       catch(e) { debugExcept(e); return false; }
  283.     }
  284.  
  285.     function CBcreateTable(desc)
  286.     {
  287.       var e;
  288.  
  289.       try
  290.       {
  291.         var conn = ADBC.newConnection(desc.DBName);
  292.         var stmt = conn ? conn.newStatement() : null;
  293.  
  294.         /* come up with the SQL query to do it */
  295.         var sql1 = "create table \"" + desc.tableName + "\" (AUTHOR varchar(64), PAGE integer, NAME varchar(64), CONTENTS text, DATA image);";
  296.         var sql2 = "create table \"" + desc.tableName + "\" (AUTHOR varchar(64), PAGE integer, NAME varchar(64), CONTENTS clob, DATA blob);";
  297.  
  298.         var conn = {conn: conn,
  299.           stmt: stmt,
  300.           tableName: desc.tableName,
  301.           user: desc.user,
  302.           flags: desc.flags};
  303.  
  304.         // first try...
  305.         try
  306.         {
  307.           stmt.execute(sql1);
  308.         } catch(e) { debugExcept(e); }
  309.         // second try...
  310.         try
  311.         {
  312.           stmt.execute(sql2);
  313.         } catch(e) { debugExcept(e); }
  314.         // these will throw if the table wasn't created
  315.         CBsetInfo(conn, "URL", desc.URL);
  316.         CBsetInfo(conn, "creator", desc.user);
  317.         return conn;
  318.       }
  319.       /* we failed... */
  320.       catch(e) { debugExcept(e); return false; }
  321.     }
  322.  
  323.     function CBconnect(desc, bDoNotCreate)
  324.     {
  325.       var conn = CBgetTableConnect(desc);
  326.       var e;
  327.  
  328.       /* if we can't get the URL from it, it doesn't exist */
  329.       if(!CBgetInfo(conn, "URL"))
  330.       {
  331.         if (!bDoNotCreate)
  332.           conn = CBcreateTable(desc);
  333.         else
  334.           return false;
  335.       }
  336.  
  337.       /* here it is! */
  338.       return conn;
  339.     }
  340.  
  341.     /* mapping of annot types to data properties */
  342.     CBannotdata =
  343.     {
  344.         FileAttachment:    "FSCosObj",
  345.         Sound:            "SCosObj"
  346.     };
  347.  
  348.     /* returns the data fork for an annot */
  349.     function CBannotData(annot)
  350.     {
  351.       var prop = CBannotdata[annot.type];
  352.       var stm = prop ? Collab.cosObj2Stream(annot[prop]) : null;
  353.  
  354.       if(stm)
  355.         stm.type = ADBC.SQLT_LONGVARBINARY;
  356.       return stm;
  357.     }
  358.  
  359.     /* sets the data fork of an annot */
  360.     function CBannotSetData(annot, data)
  361.     {
  362.       var prop = CBannotdata[annot.type];
  363.  
  364.       if(prop)
  365.         annot[prop] = data;
  366.     }
  367.  
  368.  
  369.     /* recursive function that deletes a reply chain */
  370.     function CBDeleteReplyChain(disc)
  371.     {
  372.         var replies = Discussions.getDiscussions(disc);
  373.  
  374.         if (replies && (replies.length == 1))
  375.         {
  376.             var currentReply = replies[0];
  377.             var looper = 1;
  378.             while (looper)
  379.             {
  380.                 /*
  381.                 ** There better only be one reply 
  382.                 */
  383.                 var saveChild = Discussions.getDiscussions(currentReply);
  384.  
  385.     //            console.println("Delete reply");
  386.                 currentReply.Delete();
  387.  
  388.                 if (saveChild && (saveChild.length == 1))
  389.                     currentReply = saveChild[0];
  390.                 else
  391.                     looper = 0;
  392.             }
  393.         }
  394.  
  395.     }
  396.  
  397.     /* gets the reply chain, stuffs it in a stream */
  398.     /* and then puts it in the annot */
  399.     function CBGetReplyChain(dstAnnot, discussion)
  400.     {
  401.         var discList = Discussions.getDiscussions(discussion);
  402.  
  403.         var cos = Collab.newWrStreamToCosObj();
  404.  
  405.         var data = 0;
  406.         while (discList && (discList.length > 0))
  407.         {
  408.             data = 1;
  409.             cos.write(discList[0].Text);
  410.     //        console.println("Write to cos stream " + discList[0].Text.length + " characters");
  411.  
  412.             discList = Discussions.getDiscussions(discList[0]);
  413.         }
  414.  
  415.         if (data == 1)
  416.             CBannotSetData(dstAnnot, cos.getCosObj());
  417.     }
  418.  
  419.     /* get the stream and puts the data as replies */
  420.     function CBPutReplyChain(discussion, bookmark, srcAnnot)
  421.     {
  422.         var cosStream = CBannotData(srcAnnot);
  423.  
  424.         if(cosStream)
  425.         {
  426.             var s = cosStream.read(Collab.wdBlockSize);
  427.  
  428.             while (discussion && (s.length > 0))
  429.             {
  430.                 discussion = Discussions.addDiscussion(discussion, "Data", s, bookmark);
  431.  
  432.                 s = null;
  433.             
  434.                 s = cosStream.read(Collab.wdBlockSize);
  435.             }
  436.         }
  437.     }
  438.  
  439.     /* ADBC based annot enumerator constructor
  440.     */
  441.     function ADBCAnnotEnumerator(parent, sorted)
  442.     {
  443.       /* store away parameters */
  444.       this.parent = parent;
  445.       this.sorted = sorted;
  446.       /* add enumeration method */
  447.       this.next = function()
  448.       {
  449.         var e;
  450.  
  451.         try
  452.         {
  453.           if(!this.conn)
  454.           {
  455.             this.conn = CBconnect(this.parent.desc, true);
  456.             this.conn.stmt.execute("select CONTENTS from \"" + this.parent.desc.tableName + "\" where AUTHOR not like '~%~'" +
  457.               (this.sorted ? " order by PAGE, NAME;" : ";"));
  458.           }
  459.           this.conn.stmt.nextRow();
  460.           return eval(this.conn.stmt.getColumn("CONTENTS").value);
  461.         }
  462.         catch(e) { debugExcept(e); return false; }
  463.       }
  464.     }
  465.  
  466.     /* ADBC based annot store constructor
  467.     */
  468.     function ADBCAnnotStore(doc, user)
  469.     {
  470.       this.desc = CBgetTableDesc(doc, user);
  471.       this.enumerate = function(sorted)
  472.       {
  473.         return new ADBCAnnotEnumerator(this, sorted);
  474.       }
  475.       this.complete = function(toComplete)
  476.       {
  477.         var i;
  478.         var conn = CBconnect(this.desc,true);
  479.  
  480.         if (conn) 
  481.             {
  482.           for(i = 0; toComplete && i < toComplete.length; i++)
  483.           {
  484.             if(CBannotdata[toComplete[i].type])
  485.             {
  486.               var e;
  487.   
  488.               try
  489.               {
  490.                 conn.stmt.execute("select DATA from \"" + this.desc.tableName + "\" where PAGE = ? and NAME like ?;",
  491.                   toComplete[i].page, toComplete[i].name);
  492.                 conn.stmt.nextRow();
  493.                 var cos = Collab.newWrStreamToCosObj();
  494.  
  495.                 conn.stmt.getColumn("DATA", ADBC.Binary | ADBC.Stream, cos);
  496.                 CBannotSetData(toComplete[i], cos.getCosObj());
  497.               }
  498.               catch(e) { debugExcept(e);}
  499.             }
  500.               }
  501.         }
  502.         return true;
  503.       }
  504.       this.update = function(toDelete, toAdd, toUpdate)
  505.       {
  506.         var i;
  507.         var e;
  508.         var conn = CBconnect(this.desc);
  509.  
  510.         for(i = 0; toDelete && i < toDelete.length; i++)
  511.         {
  512.           try
  513.           {
  514.             conn.stmt.execute("delete from \"" + this.desc.tableName + "\" where PAGE = ? and NAME like ?;",
  515.               toDelete[i].page, toDelete[i].name);
  516.           }
  517.           catch(e) { debugExcept(e);}
  518.         }
  519.         for(i = 0; toAdd && i < toAdd.length; i++)
  520.         {
  521.           try
  522.           {
  523.             conn.stmt.execute("insert into \"" + this.desc.tableName + "\" (AUTHOR, PAGE, NAME, CONTENTS, DATA) values (?, ?, ?, ?, ?);",
  524.               toAdd[i].author, toAdd[i].page, toAdd[i].name, toAdd[i].toSource(), CBannotData(toAdd[i]));
  525.           }
  526.           catch(e) { debugExcept(e);}
  527.         }
  528.         for(i = 0; toUpdate&& i < toUpdate.length; i++)
  529.         {
  530.           try
  531.           {
  532.             conn.stmt.execute("update \"" + this.desc.tableName + "\" set CONTENTS = ?, DATA = ? where PAGE = ? and NAME like ?;",
  533.               toUpdate[i].toSource(), CBannotData(toUpdate[i]), toUpdate[i].page, toUpdate[i].name);
  534.           }
  535.           catch(e) { debugExcept(e);}
  536.         }
  537.         return true;
  538.       }
  539.     }
  540.  
  541.     /* Munge an URL such that Web Discussions won't put our data in the discussions pane
  542.     */
  543.     function WDmungeURL(url)
  544.     {
  545.         return url + "/ACData";
  546.     }
  547.  
  548.     /* Web discussions based annot enumerator constructor
  549.     */
  550.     function WDAnnotEnumerator(parent, sorted)
  551.     {
  552.     //  console.println("WDAnnotEnumerator(): Begin");
  553.  
  554.       this.parent = parent;
  555.       this.sorted = sorted;
  556.       this.next = function()
  557.       {
  558.     //    console.println("WDAnnotEnumerator.next(): Begin");
  559.  
  560.         if(!this.discussions)
  561.         {
  562.     //        console.println("WDAnnotEnumerator.next(): get discussions "+WDmungeURL(this.parent.doc.URL));
  563.  
  564.           this.discussions = Discussions.getDiscussions(WDmungeURL(this.parent.doc.URL));
  565.  
  566.           app.thermometer.begin();
  567.           app.thermometer.text = IDS_PROGRESS_FETCHING;
  568.           if(this.discussions) // always sort as our completion callback relies on a sorted list
  569.           {
  570.             this.discussions = isort(this.discussions, IDS_PROGRESS_SORTING);
  571.             app.thermometer.duration = this.discussions.length;
  572.           }
  573.           this.index = 0;
  574.         }
  575.         /* skip non-Acro discussions */
  576.         while(this.discussions && this.index < this.discussions.length && this.discussions[this.index] == "[Discussion]")
  577.           app.thermometer.value = this.index++;
  578.         if(!this.discussions || this.index >= this.discussions.length)
  579.         {
  580.           app.thermometer.end();
  581.           return false;
  582.         }
  583.         return eval(this.discussions[this.index++].Text);
  584.       }
  585.     }
  586.  
  587.     /* Web discussion based annot store constructor
  588.     */
  589.     function WDAnnotStore(doc, user)
  590.     {
  591.     //  console.println("WDAnnotStore(): Begin");
  592.  
  593.       this.doc = doc;
  594.       this.user = user;
  595.       this.enumerate = function(sorted)
  596.       {
  597.     //    console.println("WDAnnotStore.enumerate(): Begin");
  598.         return new WDAnnotEnumerator(this, sorted);
  599.       }
  600.       this.complete = function(toComplete)
  601.       {
  602.     //    console.show();
  603.     //    console.println("WDAnnotStore.toComplete(): Begin");
  604.  
  605.         var i,j;
  606.     //    console.println("get discussions for "+WDmungeURL(this.doc.URL));
  607.         var discussions = Discussions.getDiscussions(WDmungeURL(this.doc.URL));
  608.  
  609.         if (discussions && discussions.length) 
  610.         {
  611.             // sort them to perform fast searches
  612.             // JS sort is a SLOW qsort... use our worst case N log ( N )
  613.             discussions = isort(discussions, IDS_PROGRESS_SORTING);
  614.  
  615.             app.thermometer.begin();
  616.             app.thermometer.text = IDS_PROGRESS_FETCHING_BIG;
  617.             app.thermometer.duration = toComplete.length;
  618.             for(i = 0, j = 0; discussions && (i < toComplete.length) && (j < discussions.length); app.thermometer.value = ++i)
  619.             {
  620.                 //console.println("disussion " + i);
  621.  
  622.                 // create a string that'll look like the corresponding discussion
  623.                 var discString = Discussions.makeDiscussionString(toComplete[i].page, toComplete[i].name);
  624.                 //console.println("Descriptive string \"" + discString + "\"");
  625.  
  626.                 // keep skipping annots while they are "less" than the current one
  627.                 while(discString > discussions[j])
  628.                     j++;
  629.  
  630.                 // if we found it
  631.                 if(discString == discussions[j])
  632.                 {
  633.                     //console.println("found it - Annot to Complete " + i + " is in discussion slot " + j);
  634.                     //console.println("subject "+discussions[j].Subject);
  635.  
  636.                     /*
  637.                     ** We found the discussion, now gather replys which will
  638.                     ** contain the "data" for the stream
  639.                     */
  640.                     if (CBannotdata[toComplete[i].type])
  641.                         CBGetReplyChain(toComplete[i], discussions[j]);
  642.  
  643.                 }
  644.  
  645.             }
  646.             app.thermometer.end();
  647.         }
  648.         return true;
  649.       }
  650.       this.update = function(toDelete, toAdd, toUpdate)
  651.       {
  652.     //    console.println("WDAnnotStore.update(): Begin");
  653.  
  654.         // get the list of discussions
  655.     //    console.println("WDAnnotStore.update(): get discussions "+WDmungeURL(this.doc.URL();
  656.         var discussions = Discussions.getDiscussions(WDmungeURL(this.doc.URL));
  657.         var i, j;
  658.  
  659.         // if we got any...
  660.         if(discussions && discussions.length)
  661.         {
  662.     //        console.println("WDAnnotStore.update(): got some " + discussions.length);
  663.             // sort them to perform fast searches
  664.             discussions = isort(discussions, IDS_PROGRESS_SORTING);
  665.  
  666.             // if we've got any to update
  667.             if(toUpdate && toUpdate.length)
  668.             {
  669.                 app.thermometer.begin();
  670.                 app.thermometer.text = IDS_PROGRESS_CHANGING;
  671.                 app.thermometer.duration = toUpdate.length;
  672.     //            console.println("WDAnnotStore.update(): updating " + toUpdate.length);
  673.  
  674.                 for(i = 0, j = 0; i < toUpdate.length && j < discussions.length; app.thermometer.value = ++i)
  675.                 {
  676.                   // create a string that'll look like the corresponding discussion
  677.                   var discString = Discussions.makeDiscussionString(toUpdate[i].page, toUpdate[i].name);
  678.  
  679.                   // keep skipping annots while they are "less" than the current one
  680.                   while(discString > discussions[j])
  681.                     j++;
  682.                   // if we found it
  683.                   if(discString == discussions[j])
  684.                   {
  685.                     // then update it!
  686.                     CBDeleteReplyChain(discussions[j]);
  687.                     discussions[j].Delete();
  688.  
  689.                     var bookmark = Discussions.makeBookmark(toUpdate[i].page, toUpdate[i].name);
  690.                     discussions[j] = Discussions.addDiscussion(WDmungeURL(this.doc.URL), "Markup", toUpdate[i].toSource(), bookmark);
  691.                     CBPutReplyChain(discussions[j], bookmark, toUpdate[i]);
  692.                     j++;
  693.                   }
  694.                 }
  695.                 app.thermometer.end();
  696.             }
  697.  
  698.             // delete is just like update
  699.             if(toDelete && toDelete.length) 
  700.             {
  701.                 app.thermometer.begin();
  702.                 app.thermometer.text = IDS_PROGRESS_DELETING;
  703.                 app.thermometer.duration = toDelete.length;
  704.     //            console.println("WDAnnotStore.update(): deleting " + toDelete.length);
  705.                 for(i = 0, j = 0; i < toDelete.length && j < discussions.length; app.thermometer.value = ++i)
  706.                 {
  707.                   var discString = Discussions.makeDiscussionString(toDelete[i].page, toDelete[i].name);
  708.  
  709.                   while(discString > discussions[j])
  710.                     j++;
  711.  
  712.                   if(discString == discussions[j])
  713.                   {
  714.                     CBDeleteReplyChain(discussions[j]);
  715.  
  716.                     discussions[j].Delete();
  717.  
  718.                     j++;
  719.                   }
  720.                 }
  721.                 app.thermometer.end();
  722.             }
  723.         }
  724.         if(toAdd && toAdd.length)
  725.         {
  726.             app.thermometer.begin();
  727.             app.thermometer.text = IDS_PROGRESS_ADDING;
  728.             app.thermometer.duration = toAdd.length;
  729.             for(i = 0; toAdd && i < toAdd.length; app.thermometer.value = ++i)
  730.             {
  731.               var bookmark = Discussions.makeBookmark(toAdd[i].page, toAdd[i].name);
  732.  
  733.         /*
  734.               console.println("WDAnnotStore.update(): adding " + toAdd.length);
  735.               console.println("this.doc.URL \""+ WDmungeURL(this.doc.URL) + "\"");
  736.               console.println("Markup");
  737.               console.println("toAdd[i].toSource() \""+ toAdd[i].toSource() + "\"");
  738.               console.println("bookmark \"" + bookmark + "\"");
  739.         */
  740.  
  741.               var discussion = Discussions.addDiscussion(WDmungeURL(this.doc.URL), "Markup", toAdd[i].toSource(), bookmark);
  742.  
  743.               if (discussion && CBannotdata[toAdd[i].type])
  744.                 CBPutReplyChain(discussion, bookmark, toAdd[i]);
  745.  
  746.             }
  747.             app.thermometer.end();
  748.         }
  749.         return true;
  750.       }
  751.     }
  752.  
  753.     /* Set up default annot stores */
  754.     Collab.addAnnotStore("NONE", IDS_STORE_NONE,
  755.         {create: function(doc, user, settings){ return null; }});
  756.     Collab.setStoreNoSettings("NONE", true);
  757.     if(typeof Discussions != "undefined")
  758.     {
  759.       Collab.addAnnotStore("WD", IDS_STORE_WEB_DISCUSSIONS,
  760.             {create: function(doc, user, settings){ return new WDAnnotStore(doc, user); }});
  761.         Collab.setStoreNoSettings("WD", true);
  762.     }
  763.     if(typeof ADBC != "undefined")
  764.         Collab.addAnnotStore("DB", IDS_STORE_DATABASE,
  765.             {create: function(doc, user, settings){ doc.collabDBRoot = settings; doc.collabDBFlags = CBFNiceTableName; return (settings && settings != "") ? new ADBCAnnotStore(doc, user) : null; }});
  766.     Collab.addAnnotStore("DAVFDF", IDS_STORE_DAVFDF,
  767.         {create: function(doc, user, settings){ return (settings && settings != "") ? new FSAnnotStore(doc, user, settings + doc.Collab.docID + "/", "CHTTP") : null; }});
  768.     Collab.addAnnotStore("FSFDF", IDS_STORE_FSFDF,
  769.         {create: function(doc, user, settings){ return (settings && settings != "") ? new FSAnnotStore(doc, user, settings + doc.Collab.docID + "/") : null; }});
  770.     Collab.setStoreFSBased("FSFDF", true);
  771.  
  772.     // Web Discussion data block size
  773.     Collab.wdBlockSize = 16384;
  774. }
  775.  
  776. function CBdef(a, b)
  777. {
  778.   return typeof a == "undefined" ? b : a;
  779. }
  780.  
  781. function Matrix2D(a, b, c, d, h, v)
  782. {
  783.     this.a = CBdef(a, 1);
  784.     this.b = CBdef(b, 0);
  785.     this.c = CBdef(c, 0);
  786.     this.d = CBdef(d, 1);
  787.     this.h = CBdef(h, 0);
  788.     this.v = CBdef(v, 0);
  789.     this.fromRotated = function(doc, page)
  790.     {
  791.         page = CBdef(page, 0);
  792.  
  793.         var cropBox = doc.getPageBox("Crop", page);
  794.         var mediaBox = doc.getPageBox("Media", page);
  795.         var mbHeight = mediaBox[1] - mediaBox[3];
  796.         var mbWidth = mediaBox[2] - mediaBox[0];
  797.         var rotation = doc.getPageRotation(page);
  798.         var m = new Matrix2D(1, 0, 0, 1, cropBox[0] - mediaBox[0], cropBox[3] - mediaBox[3]);
  799.  
  800.         if(rotation == 90)
  801.             return this.concat(m.rotate(Math.asin(1.0)).translate(mbHeight, 0));
  802.         else if(rotation == 180)
  803.             return this.concat(m.rotate(2.0 * -Math.asin(1.0)).translate(mbWidth, mbHeight));
  804.         else if(rotation == 270)
  805.             return this.concat(m.rotate(-Math.asin(1.0)).translate(0, mbWidth));
  806.         return this.concat(m);
  807.     }
  808.     this.transform = function(pts)
  809.     {
  810.         var result = new Array(pts.length);
  811.  
  812.         if(typeof pts[0] == "object")
  813.             for(var n = 0; n < pts.length; n++)
  814.                 result[n] = this.transform(pts[n]);
  815.         else
  816.             for(var n = 0; n + 1 < pts.length; n += 2)
  817.             {
  818.                 result[n] = this.a * pts[n] + this.c * pts[n + 1] + this.h;
  819.                 result[n + 1] = this.b * pts[n] + this.d * pts[n + 1] + this.v;
  820.             }
  821.         return result;
  822.     }
  823.     this.concat = function(m)
  824.     {
  825.         return new Matrix2D(
  826.             (this.a * m.a) + (this.b * m.c),
  827.             (this.a * m.b) + (this.b * m.d),
  828.             (this.c * m.a) + (this.d * m.c),
  829.             (this.c * m.b) + (this.d * m.d),
  830.             (this.h * m.a) + (this.v * m.c) + m.h,
  831.             (this.h * m.b) + (this.v * m.d) + m.v);
  832.     }
  833.     this.invert = function()
  834.     {
  835.         var result = new Matrix2D;
  836.         var q = this.b * this.c - this.a * this.d;
  837.  
  838.         if (q)
  839.         {
  840.             result.a = - this.d / q;
  841.             result.b = this.b / q;
  842.             result.c = this.c / q;
  843.             result.d = - this.a / q;
  844.             result.h = -(this.h * result.a + this.v * result.c);
  845.             result.v = -(this.h * result.b + this.v * result.d);
  846.         }
  847.         return result;
  848.     }
  849.     this.translate = function(dx, dy)
  850.     {
  851.         return this.concat(new Matrix2D(1, 0, 0, 1, CBdef(dx, 0), CBdef(dy, 0)));
  852.     }
  853.     this.scale = function(sx, sy)
  854.     {
  855.         return this.concat(new Matrix2D(CBdef(sx, 1), 0, 0, CBdef(sy, 1), 0, 0));
  856.     }
  857.     this.rotate = function(t)
  858.     {
  859.         t = CBdef(t, 0);
  860.         return this.concat(new Matrix2D(Math.cos(t), Math.sin(t), -Math.sin(t), Math.cos(t), 0, 0));
  861.     }
  862. }
  863.